﻿using System;
using System.Linq;
using System.Collections.Generic;

namespace Microsoft.Media.ISO
{
    public interface IBox
    {
        string Type { get; set; }
    }

    public interface IUniversalUniqueIdentifierBox : IBox
    {
        Guid Uuid { get; set; }
    }

    public interface ISampleEntryBox : IBox
    {
        ushort DataReferenceIndex { get; set; }
    }

    public interface IContainerBox : IBox
    {
        IList<IBox> InnerBoxes { get; }
    }

    public interface IFullBox : IBox
    {
        byte Version { get; set; }
        uint Flags { get; set; }
    }

    public sealed class FileTypeBox : IBox
    {
        public FileTypeBox()
        {
            Type = "ftyp";
            CompatibleBrands = new List<string>();
        }

        public string Type { get; set; }

        /// <summary>
        /// Gets or sets the brand identifier.
        /// </summary>
        public string MajorBrand { get; set; }


        /// <summary>
        /// An informative integer for the minor version of the major brand.
        /// </summary>
        public uint MinorVersion { get; set; }


        /// <summary>
        /// Represents the list of compatible brands.
        /// </summary>
        public IList<string> CompatibleBrands { get; private set; }
    }

    public sealed class UniversalUniqueIdentifierBox : IUniversalUniqueIdentifierBox
    {
        public UniversalUniqueIdentifierBox()
        {
            Type = "uuid";
        }

        public string Type { get; set; }

        public Guid Uuid { get; set; }

        public byte[] Data { get; set; }
    }

    public sealed class MovieBox : IContainerBox
    {
        public MovieBox()
        {
            Type = "moov";
            InnerBoxes = new List<IBox>();
        }

        public string Type { get; set; }
        public MovieHeaderBox MovieHeader { get { return InnerBoxes.OfType<MovieHeaderBox>().FirstOrDefault(); } }
        public ProtectionSystemSpecificHeaderBox ProtectionSystemSpecificHeader { get { return InnerBoxes.OfType<ProtectionSystemSpecificHeaderBox>().FirstOrDefault(); } }
        public IList<TrackBox> Tracks { get { return InnerBoxes.OfType<TrackBox>().ToList(); } }
        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class MovieHeaderBox : IFullBox
    {
        public MovieHeaderBox()
        {
            Type = "mvhd";
            Matrix = new uint[9];
        }

        public string Type { get; set; }
        public uint Flags { get; set; }
        public byte Version { get; set; }
        public uint TimeScale { get; set; }
        public DateTimeOffset CreationTime { get; set; }
        public DateTimeOffset ModificationTime { get; set; }
        public ulong Duration { get; set; }
        public uint NextTrackId { get; set; }
        public uint Rate { get; set; }
        public UInt16 Volume { get; set; }
        public uint[] Matrix { get; set; }
    }

    public sealed class TrackBox : IContainerBox
    {
        public TrackBox()
        {
            Type = "trak";
            InnerBoxes = new List<IBox>();
        }
        public string Type { get; set; }
        public TrackHeaderBox TrackHeader { get { return InnerBoxes.OfType<TrackHeaderBox>().FirstOrDefault(); } }
        public MediaBox Media { get { return InnerBoxes.OfType<MediaBox>().FirstOrDefault(); } }
        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class TrackHeaderBox : IFullBox
    {
        public TrackHeaderBox()
        {
            Type = "tkhd";
            Matrix = new uint[9];
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        /// <summary>
        /// Declares the creation time of this track (in seconds since midnight, Jan. 1, 1904, in UTC time).
        /// </summary>
        public DateTimeOffset CreationTime { get; set; }

        /// <summary>
        /// An integer that declares the most recent time the track was modified (in seconds since midnight, Jan. 1, 1904, in UTC time).
        /// </summary>
        public DateTimeOffset ModificationTime { get; set; }

        /// <summary>
        /// An integer that indicates the duration of this track (in the timescale indicated in the Movie Header Box). 
        /// </summary>
        public ulong Duration { get; set; }

        /// <summary>
        /// Specify the track's visual presentation size as fixed-point 16.16 values. Width and height for a track with no video MUST be 0.
        /// </summary>
        public uint Height { get; set; }

        /// <summary>
        /// Specify the track's visual presentation size as fixed-point 16.16 values. Width and height for a track with no video MUST be 0.
        /// </summary>
        public uint Width { get; set; }

        /// <summary>
        /// Specifies the front-to-back ordering of video tracks. Tracks with lower numbers are closer to the viewer. 0 is the normal value, -1 would be in front of track 0, and so on.
        /// </summary>
        public ushort Layer { get; set; }

        /// <summary>
        /// An integer that specifies a group or collection of tracks. If this field is 0, there is no information on possible relations to other tracks. 
        /// If this field is not 0, it should be the same for tracks that contain alternate data for one another and different for tracks belonging to different groups. 
        /// Only one track within an alternate group should be played or streamed at any one time, and it must be distinguishable from other tracks in the group via attributes     
        /// such as bit rate, codec, language, packet size, and so on. A group may have only one member.
        /// </summary>
        public ushort AlternateGroup { get; set; }

        /// <summary>
        /// An integer that uniquely identifies this track over the entire lifetime of this presentation. Track IDs are never reused and cannot be zero.
        /// </summary>
        public uint TrackId { get; set; }

        /// <summary>
        /// A fixed 8.8 value specifying the track's relative audio volume. Full volume is 1.0 (0x0100) and is the normal value. 
        /// Its value is irrelevant for a track that contains no audio. Tracks may be composed by combining them according to their volume, and then use 
        /// the overall Movie Header Box volume setting. More complex audio composition (e.g., MPEG-4 BIFS) may also be used.
        /// </summary>
        public ushort Volume { get; set; }
        public uint[] Matrix { get; set; }
    }

    public sealed class MediaBox : IContainerBox
    {
        public MediaBox()
        {
            Type = "mdia";
            InnerBoxes = new List<IBox>();
        }

        public string Type { get; set; }
        public MediaHeaderBox MediaHeader { get { return InnerBoxes.OfType<MediaHeaderBox>().FirstOrDefault(); } }
        public HandlerReferenceBox HandlerReference { get { return InnerBoxes.OfType<HandlerReferenceBox>().FirstOrDefault(); } }
        public MediaInformationBox MediaInformation { get { return InnerBoxes.OfType<MediaInformationBox>().FirstOrDefault(); } }
        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class MediaHeaderBox : IFullBox
    {
        public MediaHeaderBox()
        {
            Type = "mdhd";
        }

        public string Type { get; set; }
        public byte Version { get; set; }
        public uint Flags { get; set; }

        public DateTimeOffset CreationTime { get; set; }

        public DateTimeOffset ModificationTime { get; set; }

        /// <summary>
        /// Gets the timescale for the media in the track.
        /// </summary>
        public uint Timescale { get; set; }

        /// <summary>
        /// Gets the timescale for the duration of the media in the track.
        /// </summary>
        public ulong Duration { get; set; }

        /// <summary>
        /// Gets the ISO-639-2 three character language code for the track.
        /// </summary>
        public string Language { get; set; }

        public ushort Quality { get; set; }
    }

    public sealed class HandlerReferenceBox : IFullBox
    {
        public HandlerReferenceBox()
        {
            Type = "hdlr";
        }

        public string Type { get; set; }
        public byte Version { get; set; }

        public uint Flags { get; set; }

        /// <summary>
        /// When present in a media box, an integer containing either one of the following values or a value from a derived specification:
        ///     'vide': Video track
        ///     'soun': Audio track
        ///     'hint': Hint track
        /// </summary>
        public string HandlerType { get; set; }

        /// <summary>
        /// A null-terminated string in UTF-8 characters which gives a human-readable name for the track type (for debugging and inspection purposes).
        /// </summary>
        public string Name { get; set; }
    }

    public sealed class MediaInformationBox : IContainerBox
    {
        public MediaInformationBox()
        {
            Type = "minf";
            InnerBoxes = new List<IBox>();
        }
        public string Type { get; set; }
        public SoundMediaHeaderBox SoundMediaHeader { get { return InnerBoxes.OfType<SoundMediaHeaderBox>().FirstOrDefault(); } }
        public VideoMediaHeaderBox VideoMediaHeader { get { return InnerBoxes.OfType<VideoMediaHeaderBox>().FirstOrDefault(); } }
        public DataInformationBox DataInformation { get { return InnerBoxes.OfType<DataInformationBox>().FirstOrDefault(); } }
        public SampleTableBox SampleTable { get { return InnerBoxes.OfType<SampleTableBox>().FirstOrDefault(); } }
        public NullMediaHeaderBox NullMediaHeader { get { return InnerBoxes.OfType<NullMediaHeaderBox>().FirstOrDefault(); } }
        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class SyncSamplesBox : IFullBox
    {
        public SyncSamplesBox()
        {
            Type = "stss";
            SyncTable = new List<uint>();
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        /// <summary>
        /// A table of sample numbers that are also sync samples; the table is sorted in ascending order of sample numbers.
        /// </summary>
        public IList<uint> SyncTable { get; private set; }
    }

    public sealed class SoundMediaHeaderBox : IFullBox
    {
        public SoundMediaHeaderBox()
        {
            Type = "smhd";
        }

        public string Type { get; set; }
        public byte Version { get; set; }
        public uint Flags { get; set; }
        public uint Balance { get; set; }
    }

    public sealed class VideoMediaHeaderBox : IFullBox
    {
        public VideoMediaHeaderBox()
        {
            Type = "vmhd";
            Color = new ushort[3];
        }

        public string Type { get; set; }
        public byte Version { get; set; }
        public uint Flags { get; set; }
        public ushort GraphicsMode { get; set; }
        public ushort[] Color { get; set; }
    }

    public sealed class DataInformationBox : IContainerBox
    {
        public DataInformationBox()
        {
            Type = "dinf";
            InnerBoxes = new List<IBox>();
        }
        public string Type { get; set; }
        public DataReferenceBox DataReference { get { return InnerBoxes.OfType<DataReferenceBox>().FirstOrDefault(); } }
        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class DataReferenceBox : IFullBox, IContainerBox
    {
        public DataReferenceBox()
        {
            Type = "dref";
            InnerBoxes = new List<IBox>();
        }
        public string Type { get; set; }
        public byte Version { get; set; }
        public uint Flags { get; set; }
        public UrlBox Url { get { return InnerBoxes.OfType<UrlBox>().FirstOrDefault(); } }
        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class UrlBox : IFullBox
    {
        public UrlBox()
        {
            Type = "url ";
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        public uint Flags { get; set; }
    }

    public sealed class SampleTableBox : IContainerBox
    {
        public SampleTableBox()
        {
            Type = "stbl";
            InnerBoxes = new List<IBox>();
        }
        public string Type { get; set; }
        public DecodingTimeToSampleBox DecodingTimeToSample { get { return InnerBoxes.OfType<DecodingTimeToSampleBox>().FirstOrDefault(); } }
        public CompositionTimeToSampleBox CompositionTimeToSample { get { return InnerBoxes.OfType<CompositionTimeToSampleBox>().FirstOrDefault(); } }
        public SampleChunkBox SampleChunk { get { return InnerBoxes.OfType<SampleChunkBox>().FirstOrDefault(); } }
        public SampleChunkOffsetBox SampleChunkOffset { get { return InnerBoxes.OfType<SampleChunkOffsetBox>().FirstOrDefault(); } }
        public SampleSizeBox SampleSize { get { return InnerBoxes.OfType<SampleSizeBox>().FirstOrDefault(); } }
        public SampleDescriptionBox SampleDescription { get { return InnerBoxes.OfType<SampleDescriptionBox>().FirstOrDefault(); } }
        public DfxpBox Dfxp { get { return InnerBoxes.OfType<DfxpBox>().FirstOrDefault(); } }
        public SyncSamplesBox SyncSamples { get { return InnerBoxes.OfType<SyncSamplesBox>().FirstOrDefault(); } }
        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class NullMediaHeaderBox : IFullBox
    {
        public NullMediaHeaderBox()
        {
            Type = "nmhd";
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        public uint Flags { get; set; }
    }

    public sealed class UserDataBox : IContainerBox
    {
        public UserDataBox()
        {
            Type = "udta";
            InnerBoxes = new List<IBox>();
        }

        public string Type { get; set; }

        public MetaBox Meta { get { return InnerBoxes.OfType<MetaBox>().FirstOrDefault(); } }

        public XtraBox Xtra { get { return InnerBoxes.OfType<XtraBox>().FirstOrDefault(); } }

        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class MetaBox : IFullBox, IContainerBox
    {
        public MetaBox()
        {
            Type = "meta";
            InnerBoxes = new List<IBox>();
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        public HandlerReferenceBox HandlerReference { get { return InnerBoxes.OfType<HandlerReferenceBox>().FirstOrDefault(); } }

        public ItemListBox ItemList { get { return InnerBoxes.OfType<ItemListBox>().FirstOrDefault(); } }

        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class AssetInformationBox : IBox, IFullBox
    {
        public AssetInformationBox()
        {
            Type = "ainf";
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        public string ProfileVersion { get; set; }
        public string Apid { get; set; }
    }

    public sealed class ItemListBox : IBox
    {
        public ItemListBox()
        {
            Type = "ilst";
        }

        public byte[] Data { get; set; }

        public string Type { get; set; }
    }

    public sealed class XtraBox : IBox
    {
        public XtraBox()
        {
            Type = "Xtra";
        }

        public byte[] Data { get; set; }

        public string Type { get; set; }
    }

    public sealed class DecodingTimeToSampleBox : IFullBox
    {
        public DecodingTimeToSampleBox()
        {
            Type = "stts";
            Entries = new List<DecodingTimeToSampleBoxEntry>();
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        /// <summary>
        /// An array of STTSRECORD structures.
        /// </summary>
        public IList<DecodingTimeToSampleBoxEntry> Entries { get; private set; }
    }

    public sealed class DecodingTimeToSampleBoxEntry
    {
        /// <summary>
        /// The number of consecutive samples that this STTSRECORD applies to
        /// </summary>
        public uint SampleCount { get; set; }

        /// <summary>
        /// Sample duration
        /// </summary>
        public uint SampleDelta { get; set; }
    }

    public sealed class CompositionTimeToSampleBox : IFullBox
    {
        public CompositionTimeToSampleBox()
        {
            Type = "ctts";
            Entries = new List<CompositionTimeToSampleBoxEntry>();
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        public IList<CompositionTimeToSampleBoxEntry> Entries { get; private set; }
    }

    public sealed class CompositionTimeToSampleBoxEntry
    {
        public uint SampleCount { get; set; }
        public uint SampleOffset { get; set; }
    }

    public sealed class SampleChunkBox : IFullBox
    {
        public SampleChunkBox()
        {
            Type = "stsc";
            Entries = new List<SampleChunkBoxEntry>();
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        public IList<SampleChunkBoxEntry> Entries { get; private set; }
    }

    public sealed class SampleChunkBoxEntry
    {
        public uint FirstChunk { get; set; }
        public uint SamplesPerChunk { get; set; }
        public uint SampleDescIndex { get; set; }
    }

    public sealed class SampleChunkOffsetBox : IFullBox
    {
        public SampleChunkOffsetBox()
        {
            Type = "stco";
            Offsets = new List<uint>();
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        /// <summary>
        /// A table of absolute chunk offsets within the file
        /// </summary>
        public IList<uint> Offsets { get; private set; }
    }

    public sealed class SampleSizeBox : IFullBox
    {
        public SampleSizeBox()
        {
            Type = "stsz";
            SizeTable = new List<uint>();
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        /// <summary>
        /// If all samples have the same size, this field is set with that constant size; otherwise it is 0
        /// </summary>
        public uint ConstantSize { get; set; }

        /// <summary>
        /// A table of sample sizes; if ConstantSize is 0, this table is empty
        /// </summary>
        public IList<uint> SizeTable { get; private set; }
    }

    public sealed class MovieExtendsBox : IContainerBox
    {
        public MovieExtendsBox()
        {
            Type = "mvex";
            InnerBoxes = new List<IBox>();
        }

        public string Type { get; set; }

        public IList<TrackExtendsBox> TrackExtends { get { return InnerBoxes.OfType<TrackExtendsBox>().ToList(); } }
        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class TrackExtendsBox : IFullBox
    {
        public TrackExtendsBox()
        {
            Type = "trex";
        }

        public string Type { get; set; }
        public byte Version { get; set; }
        public uint Flags { get; set; }
        public uint TrackId { get; set; }
        public uint SampleDescriptionIndex { get; set; }
        public uint SampleDuration { get; set; }
        public uint SampleSize { get; set; }
        public SampleFlags SampleFlags { get; set; }
    }

    public sealed class MovieFragmentRandomAccessBox : IContainerBox
    {
        public MovieFragmentRandomAccessBox()
        {
            Type = "mfra";
            InnerBoxes = new List<IBox>();
        }

        public string Type { get; set; }
        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class TrackFragmentRandomAccessBox : IFullBox
    {
        public TrackFragmentRandomAccessBox()
        {
            Type = "tfra";
            TrackFragmentRandomAccessEntries = new List<TrackFragmentRandomAccessEntry>();
        }

        public string Type { get; set; }
        public byte Version { get; set; }
        public uint Flags { get; set; }

        /// <summary>
        /// Gets the length size of sample num.
        /// </summary>
        public byte LengthSizeOfSampleNum { get; set; }

        /// <summary>
        /// Indicates the length in bytes of the traf_number field minus one.
        /// </summary>
        public byte LengthSizeOfTrafNum { get; set; }

        /// <summary>
        /// Indicates the length in bytes of the trun_number field minus one.
        /// </summary>
        public byte LengthSizeOfTrunNum { get; set; }

        /// <summary>
        /// An integer identifying the track ID.
        /// </summary>
        public uint TrackId { get; set; }

        /// <summary>
        /// Gets or sets the tfra entries list.
        /// </summary>      
        public IList<TrackFragmentRandomAccessEntry> TrackFragmentRandomAccessEntries { get; private set; }
    }

    /// <summary>
    /// Defines the information for each track entry.
    /// </summary>
    public sealed class TrackFragmentRandomAccessEntry
    {
        /// <summary>
        /// An integer that gives the offset of the 'moof' used in this entry. Offset is the byte-offset between the beginning of the file and the beginning of the 'moof'.
        /// </summary>
        public ulong MoofOffset { get; internal set; }
        /// <summary>
        /// Indicates the sample number that contains the random accessible sample. The number ranges from 1 in each 'trun'.
        /// </summary>
        public uint SampleNumber { get; internal set; }
        /// <summary>
        /// An integer that indicates the presentation time of the random access sample in units defined in the 'mdhd' of the associated track.
        /// </summary>
        public ulong Time { get; internal set; }
        /// <summary>
        /// Indicates the 'traf' number that contains the random accessible sample. The number ranges from 1 (the first traf is numbered 1) in each 'moof'.
        /// </summary>
        public uint TrafNumber { get; internal set; }
        /// <summary>
        /// Indicates the 'trun' number that contains the random accessible sample. The number ranges from 1 in each 'traf'.
        /// </summary>
        public uint TrunNumber { get; internal set; }
        /// <summary>
        /// An integer that indicates how large the sample is.
        /// </summary>
        public ulong SampleSize { get; set; }
    }

    public sealed class SampleDescriptionBox : IFullBox, IContainerBox
    {
        public SampleDescriptionBox()
        {
            Type = "stsd";
            InnerBoxes = new List<IBox>();
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        public IList<ISampleEntryBox> SampleEntries { get { return InnerBoxes.OfType<ISampleEntryBox>().ToList(); } }

        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class DfxpBox : ISampleEntryBox
    {
        public DfxpBox()
        {
            Type = "dfxp";
        }

        public string Type { get; set; }

        public ushort DataReferenceIndex { get; set; }
    }

    public sealed class SubtitleSampleEntryBox : ISampleEntryBox, IContainerBox
    {
        public SubtitleSampleEntryBox()
        {
            Type = "stpp";
            InnerBoxes = new List<IBox>();
        }

        public string Type { get; set; }

        public ushort DataReferenceIndex { get; set; }

        public string Namespace { get; set; }
        public string SchemaLocation { get; set; }
        public string ImageMimeType { get; set; }

        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class AudioSampleEntryBox : ISampleEntryBox, IContainerBox
    {
        public AudioSampleEntryBox()
        {
            InnerBoxes = new List<IBox>();
        }

        public string Type { get; set; }

        public ushort DataReferenceIndex { get; set; }

        public ElementaryStreamDescriptorBox ElementaryStreamDescriptor { get { return InnerBoxes.OfType<ElementaryStreamDescriptorBox>().FirstOrDefault(); } }

        /// <summary>
        /// Either 1 (mono) or 2 (stereo).
        /// </summary>
        public ushort ChannelCount { get; set; }

        /// <summary>
        /// Specifies the precision of each elementary sample in bits.
        /// </summary>
        public ushort SampleSize { get; set; }

        /// <summary>
        /// The elementary sampling rate expressed as a 16.16 fixed-point number (hi.lo) in samples per second. If the sample rate exceeds 64k, 
        /// <see cref="SampleRate"/> is set to 0 and the information in the wave_format_ex_data field in the owma box is used to indicate this instead.
        /// </summary>
        public uint SampleRate { get; set; }

        public ushort AudioEncodingVersion { get; set; }

        public ushort AudioEncodingRevisionLevel { get; set; }

        public string AudioEncodingVendor { get; set; }

        public ushort AudioCompressionId { get; set; }

        public ushort AudioPacketSize { get; set; }

        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class VisualSampleEntryBox : ISampleEntryBox, IContainerBox
    {
        public VisualSampleEntryBox()
        {
            InnerBoxes = new List<IBox>();
        }

        public string Type { get; set; }

        public ushort DataReferenceIndex { get; set; }

        /// <summary>
        /// A name, for informative purposes. It is formatted in a fixed 32-byte field, with the first byte set to the number of bytes to be displayed, 
        /// followed by the number of bytes of displayable data, and then padding to complete 32 bytes total (including the size byte). The field may be set to 0.
        /// </summary>        
        public string CompressorName { get; set; }

        /// <summary>
        /// Takes one of the following values:
        /// 	0x0018: Images are in color with no alpha
        /// </summary>
        public ushort Depth { get; set; }

        /// <summary>
        /// Indicates how many frames of compressed video are stored in each sample. The default is 1 (one frame per sample). It may be more than 1 for multiple frames per sample.
        /// </summary>
        public ushort FrameCount { get; set; }

        /// <summary>
        /// The maximum visual height of the stream are described by this sample description, in pixels.
        /// </summary>
        public ushort Height { get; set; }

        /// <summary>
        /// Gives the horizontal resolution of the image in pixels-per-inch, as a fixed 16.16 number.
        /// </summary>
        public uint HorizResolution { get; set; }

        /// <summary>
        /// Gives the vertical resolution of the image in pixels-per-inch, as a fixed 16.16 number.
        /// </summary>
        public uint VertResolution { get; set; }

        /// <summary>
        /// The maximum visual width of the stream are described by this sample description, in pixels.
        /// </summary>
        public ushort Width { get; set; }

        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class AdvancedVideoCodingBox : IBox
    {
        public AdvancedVideoCodingBox()
        {
            Type = "avcC";
            this.SequenceParameters = new List<IList<byte>>();
            this.PictureParameters = new List<IList<byte>>();
        }

        public string Type { get; set; }
        /// <summary>
        /// Bit map indicating which profiles this stream is compatible, as defined in the AVC specification [ISO/IEC 14496-10 | ITU Recommendation H.264]. 
        /// </summary>
        public byte AvcCompatibleProfiles { get; set; }
        /// <summary>
        /// Level code defined in Annex A of the AVC specification [ISO/IEC 14496-10 | ITU Recommendation H.264]. 
        /// </summary>
        public byte AvcLevelIndication { get; set; }
        /// <summary>
        /// Profile code defined in Annex A of the AVC specification [ISO/IEC 14496-10 | ITU Recommendation H.264]. 
        /// </summary>
        public byte AvcProfileIndication { get; set; }
        /// <summary>
        /// Gets the configuration version.
        /// </summary>
        public byte ConfigurationVersion { get; set; }
        /// <summary>
        /// Length in bytes of the NALUnitLength field in an AVC video sample of the associated stream. 
        /// </summary>
        public byte NaluLengthSize { get; set; }
        /// <summary>
        /// Picture parameter set NAL Unit, as specified in ISO/IEC 14496-10. 
        /// Picture parameter sets shall occur in order of ascending parameter set identifier with gaps being allowed. 
        /// </summary>
        public IList<IList<byte>> PictureParameters { get; private set; }
        /// <summary>
        /// Sequence parameter set NAL Unit, as specified in ISO/IEC 14496-10. 
        /// Sequence parameter sets shall occur in order of ascending parameter set identifier with gaps being allowed. 
        /// </summary>
        public IList<IList<byte>> SequenceParameters { get; private set; }
    }

    public sealed class ElementaryStreamDescriptorBox : IFullBox
    {
        public ElementaryStreamDescriptorBox()
        {
            Type = "esds";
        }

        public string Type { get; set; }
        public byte Version { get; set; }
        public uint Flags { get; set; }
        public IDescriptor StreamDescriptor { get; set; }
    }

    public sealed class ElementaryStreamDescriptor : IDescriptor
    {
        public ElementaryStreamDescriptor()
        {
            Tag = DescriptorTag.ES;
            SubDescriptors = new List<IDescriptor>();
        }

        /// <summary>
        /// Gets the size of the header.
        /// </summary>
        public uint HeaderSize { get; set; }

        /// <summary>
        /// Gets the size of the payload.
        /// </summary>
        public uint PayloadSize { get; set; }

        /// <summary>
        /// Gets the descriptor tag.
        /// </summary>
        public DescriptorTag Tag { get; set; }

        /// <summary>
        /// Gets the list of sub descriptors
        /// </summary>
        public IList<IDescriptor> SubDescriptors { get; private set; }

        /// <summary>
        /// Gets the descriptor identifier on which this descriptor depends on.
        /// </summary>
        public ushort DependsOn { get; set; }
        /// <summary>
        /// Gets the elementary stream id.
        /// </summary>
        public ushort ElementaryStreamId { get; set; }
        /// <summary>
        /// Gets the desctiptor flags.
        /// </summary>
        public uint Flags { get; set; }
        /// <summary>
        /// Gets the ocr elementary stream id.
        /// </summary>
        public ushort OcrElementaryStreamId { get; set; }
        /// <summary>
        /// Gets the stream priority.
        /// </summary>
        public byte StreamPriority { get; set; }

        /// <summary>
        /// Gets the URL.
        /// </summary>
        public string Url { get; set; }
    }

    /// <summary>
    /// Descriptor information for this stream decoder
    /// </summary>
    public sealed class DecoderConfigurationDescriptor : IDescriptor
    {
        public DecoderConfigurationDescriptor()
        {
            Tag = DescriptorTag.DECODER_CONFIG;
            SubDescriptors = new List<IDescriptor>();
        }

        /// <summary>
        /// Gets the size of the header.
        /// </summary>
        public uint HeaderSize { get; set; }

        /// <summary>
        /// Gets the size of the payload.
        /// </summary>
        public uint PayloadSize { get; set; }

        /// <summary>
        /// Gets the descriptor tag.
        /// </summary>
        public DescriptorTag Tag { get; set; }

        /// <summary>
        /// Gets the list of sub descriptors
        /// </summary>
        public IList<IDescriptor> SubDescriptors { get; private set; }

        /// <summary>
        /// Gets the average bitrate.
        /// </summary>
        public uint AverageBitrate { get; set; }
        /// <summary>
        /// Gets the size of the buffer.
        /// </summary>
        public uint BufferSize { get; set; }
        /// <summary>
        /// Gets the max bitrate.
        /// </summary>
        public uint MaxBitrate { get; set; }
        /// <summary>
        /// Gets the object type indication.
        /// </summary>
        public DecoderObjectTypes ObjectTypeIndication { get; set; }
        /// <summary>
        /// Gets the type of the stream.
        /// </summary>
        public byte StreamType { get; set; }
        /// <summary>
        /// Gets a value indicating whether this is an up stream.
        /// </summary>
        public bool UpStream { get; set; }

    }

    /// <summary>
    /// Enumerates the several decoder object types
    /// </summary>
    public enum DecoderObjectTypes
    {
        /// <summary>
        /// Visual ISO/IEC 10918-1
        /// </summary>
        JPEG = 0x6c,
        /// <summary>
        /// Audio ISO/IEC 11172-3
        /// </summary>
        MPEG1_AUDIO = 0x6b,
        /// <summary>
        /// Visual ISO/IEC 11172-2
        /// </summary>
        MPEG1_VISUAL = 0x6a,
        /// <summary>
        /// Audio ISO/IEC 13818-7 LowComplexity Profile
        /// </summary>
        MPEG2_AAC_AUDIO_LC = 0x67,
        /// <summary>
        /// Audio ISO/IEC 13818-7 Main Profile
        /// </summary>
        MPEG2_AAC_AUDIO_MAIN = 0x66,
        /// <summary>
        /// Audio ISO/IEC 13818-7 Scaleable Sampling Rate Profile
        /// </summary>
        MPEG2_AAC_AUDIO_SSRP = 0x68,
        /// <summary>
        /// Audio ISO/IEC 13818-3
        /// </summary>
        MPEG2_PART3_AUDIO = 0x69,
        /// <summary>
        /// Visual ISO/IEC 13818-2 422 Profile
        /// </summary>
        MPEG2_VISUAL_422 = 0x65,
        /// <summary>
        /// Visual ISO/IEC 13818-2 High Profile
        /// </summary>
        MPEG2_VISUAL_HIGH = 0x64,
        /// <summary>
        /// Visual ISO/IEC 13818-2 Main Profile
        /// </summary>
        MPEG2_VISUAL_MAIN = 0x61,
        /// <summary>
        /// Visual ISO/IEC 13818-2 Simple Profile
        /// </summary>
        MPEG2_VISUAL_SIMPLE = 0x60,
        /// <summary>
        /// Visual ISO/IEC 13818-2 SNR Profile
        /// </summary>
        MPEG2_VISUAL_SNR = 0x62,
        /// <summary>
        /// Visual ISO/IEC 13818-2 Spatial Profile
        /// </summary>
        MPEG2_VISUAL_SPATIAL = 0x63,
        /// <summary>
        /// Audio ISO/IEC 14496-3
        /// </summary>
        MPEG4_AUDIO = 0x40,
        /// <summary>
        /// Systems ISO/IEC 14496-1
        /// </summary>
        MPEG4_SYSTEM = 1,
        /// <summary>
        /// Systems ISO/IEC 14496-1
        /// </summary>
        MPEG4_SYSTEM_COR = 2,
        /// <summary>
        /// Text Stream
        /// </summary>
        MPEG4_TEXT = 8,
        /// <summary>
        /// Visual ISO/IEC 14496-2
        /// </summary>
        MPEG4_VISUAL = 0x20
    }

    /// <summary>
    /// Defines specific decoder information.
    /// </summary>
    public sealed class DecoderSpecificInformationDescriptor : IDescriptor
    {
        public DecoderSpecificInformationDescriptor()
        {
            Tag = DescriptorTag.DECODER_SPECIFIC_INFO;
            SubDescriptors = new List<IDescriptor>();
        }

        /// <summary>
        /// Gets the size of the header.
        /// </summary>
        public uint HeaderSize { get; set; }

        /// <summary>
        /// Gets the size of the payload.
        /// </summary>
        public uint PayloadSize { get; set; }

        /// <summary>
        /// Gets the descriptor tag.
        /// </summary>
        public DescriptorTag Tag { get; set; }

        /// <summary>
        /// Gets the list of sub descriptors
        /// </summary>
        public IList<IDescriptor> SubDescriptors { get; private set; }

        /// <summary>
        /// Gets the decoder specific information.
        /// </summary>
        public byte[] Information { get; set; }
    }

    /// <summary>
    /// Defines the syncronization configuration descriptor
    /// </summary>
    public sealed class SyncronizationConfigurationDescriptor : IDescriptor
    {
        public SyncronizationConfigurationDescriptor()
        {
            Tag = DescriptorTag.SL_CONFIG;
            SubDescriptors = new List<IDescriptor>();
        }

        /// <summary>
        /// Gets the size of the header.
        /// </summary>
        public uint HeaderSize { get; set; }

        /// <summary>
        /// Gets the size of the payload.
        /// </summary>
        public uint PayloadSize { get; set; }

        /// <summary>
        /// Gets the descriptor tag.
        /// </summary>
        public DescriptorTag Tag { get; set; }

        /// <summary>
        /// Gets the list of sub descriptors
        /// </summary>
        public IList<IDescriptor> SubDescriptors { get; private set; }

        /// <summary>
        /// Gets the decoder specific information.
        /// </summary>
        public byte Predefined { get; set; }
    }

    public interface IDescriptor
    {
        /// <summary>
        /// Gets the size of the header.
        /// </summary>
        uint HeaderSize { get; set; }

        /// <summary>
        /// Gets the size of the payload.
        /// </summary>
        uint PayloadSize { get; set; }

        /// <summary>
        /// Gets the descriptor tag.
        /// </summary>
        DescriptorTag Tag { get; set; }

        /// <summary>
        /// Gets the list of sub-descriptors.
        /// </summary>
        IList<IDescriptor> SubDescriptors { get; }
    }

    /// <summary>
    /// Enumerates the possible values for a descriptor tag.
    /// </summary>
    public enum DescriptorTag : int
    {
        DECODER_CONFIG = 4,
        DECODER_SPECIFIC_INFO = 5,
        ES = 3,
        ES_ID_INC = 14,
        ES_ID_REF = 15,
        IOD = 2,
        IPMP_DESCRIPTOR = 11,
        IPMP_DESCRIPTOR_POINTER = 10,
        MP4_IOD = 0x10,
        MP4_OD = 0x11,
        OD = 1,
        SL_CONFIG = 6
    }

    public sealed class MovieFragmentBox : IContainerBox
    {
        public MovieFragmentBox()
        {
            Type = "moof";
            InnerBoxes = new List<IBox>();
        }

        public string Type { get; set; }
        public MovieFragmentHeaderBox MovieFragmentHeader { get { return InnerBoxes.OfType<MovieFragmentHeaderBox>().FirstOrDefault(); } }
        public TrackFragmentBox TrackFragment { get { return InnerBoxes.OfType<TrackFragmentBox>().FirstOrDefault(); } }
        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class MovieFragmentHeaderBox : IFullBox
    {
        public MovieFragmentHeaderBox()
        {
            Type = "mfhd";
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        /// <summary>
        /// Gets or sets the sequence number. The sequence number is a 1-indexed ordinal: the Nth Movie Fragment in the file has sequence number N.
        /// </summary>
        /// <value>
        /// The sequence number is a 1-indexed ordinal: the Nth Movie Fragment in the file has sequence number N.
        /// </value>
        public uint SequenceNumber { get; set; }
    }

    public sealed class SegmentIndexBox : IFullBox
    {
        public SegmentIndexBox()
        {
            Type = "sidx";
            Subsegments = new List<Subsegment>();
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        public uint ReferenceId { get; set; }
        public uint Timescale { get; set; }
        public ulong EarliestPresentationTime { get; set; }
        public ulong FirstOffset { get; set; }
        public IList<Subsegment> Subsegments { get; private set; }
    }

    public sealed class Subsegment
    {
        public uint Duration { get; set; }
        public bool ReferenceType { get; set; }
        public uint ReferencedSize { get; set; }
        public bool StartsWithSAP { get; set; }
        public ushort SAPType { get; set; }
        public uint SAPDeltaTime { get; set; }
    }

    public sealed class ProtectionSystemSpecificHeaderBox : IFullBox
    {
        public ProtectionSystemSpecificHeaderBox()
        {
            Type = "pssh";
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        /// <summary>
        /// Specifies the Content Protection System that the data box is targeted to, as a UUID for the target System. 
        /// Supported values:
        ///     9A04F079-9840-4286-AB92-E65BE0885F95 – PlayReady
        /// </summary>
        public Guid SystemId { get; set; }

        /// <summary>
        /// Specifies raw header data, in a format specific to the system.
        /// </summary>
        public byte[] Data { get; set; }
    }

    public sealed class ProtectedSchemeInformationBox : IContainerBox
    {
        public ProtectedSchemeInformationBox()
        {
            Type = "sinf";
            InnerBoxes = new List<IBox>();
        }

        public string Type { get; set; }

        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class SchemeInformationBox : IContainerBox
    {
        public SchemeInformationBox()
        {
            Type = "schi";
            InnerBoxes = new List<IBox>();
        }

        public string Type { get; set; }

        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class FreeSpaceBox : IBox
    {
        public FreeSpaceBox()
        {
            Type = "free";
        }

        public string Type { get; set; }

        public uint Size { get; set; }
    }

    public sealed class FormatBox : IBox
    {
        public FormatBox()
        {
            Type = "free";
        }

        public string Type { get; set; }

        public string Format { get; set; }
    }

    public sealed class SchemeTypeBox : IFullBox
    {
        public SchemeTypeBox()
        {
            Type = "schm";
        }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        public string Type { get; set; }

        public string SchemeType { get; set; }
        public uint SchemeVersion { get; set; }
        public string SchemeUri { get; set; }
    }

    public sealed class MovieExtendsHeaderBox : IFullBox
    {
        public MovieExtendsHeaderBox()
        {
            Type = "mehd";
        }

        public string Type { get; set; }
        public byte Version { get; set; }
        public uint Flags { get; set; }

        public ulong FragmentDuration { get; set; }
    }

    public sealed class TrackFragmentBaseMediaDecodeTimeBox : IFullBox
    {
        public TrackFragmentBaseMediaDecodeTimeBox()
        {
            Type = "tfdt";
        }

        public string Type { get; set; }
        public byte Version { get; set; }
        public uint Flags { get; set; }

        public ulong BaseMediaDecodeTime { get; set; }
    }

    public sealed class TrackEncryptionBox : IFullBox
    {
        public TrackEncryptionBox()
        {
            Type = "tenc";
        }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        public string Type { get; set; }

        public uint DefaultIsEntrypted { get; set; }
        public byte DefaultIVSize { get; set; }
        public Guid DefaultKID { get; set; }
    }

    public sealed class TrackFragmentBox : IContainerBox
    {
        public TrackFragmentBox()
        {
            Type = "traf";
            InnerBoxes = new List<IBox>();
        }
        public string Type { get; set; }
        public TrackFragmentHeaderBox TrackFragmentHeader { get { return InnerBoxes.OfType<TrackFragmentHeaderBox>().FirstOrDefault(); } }
        public TrackFragmentRunBox TrackFragmentRun { get { return InnerBoxes.OfType<TrackFragmentRunBox>().FirstOrDefault(); } }
        public IndependentAndDisposableSamplesBox IndependentAndDisposableSamples { get { return InnerBoxes.OfType<IndependentAndDisposableSamplesBox>().FirstOrDefault(); } }
        public UniversalUniqueIdentifierBox UniversalUniqueIdentifier { get { return InnerBoxes.OfType<UniversalUniqueIdentifierBox>().FirstOrDefault(); } }
        public IList<IBox> InnerBoxes { get; private set; }
    }

    public sealed class TrackFragmentHeaderBox : IFullBox
    {
        public TrackFragmentHeaderBox()
        {
            Type = "tfhd";
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        /// <summary>
        /// The sample flags field in sample fragments. is coded as a 32-bit value. 
        /// The following flags are defined in the tf_flags:
        /// 0x000001 (base-data-offset-present). Indicates the definition of the <see cref="BaseDataOffset"/> field. 
        ///     This provides an explicit anchor for the data offsets in each track run (see below). If not provided, 
        ///     the base-data-offset for the first track in the movie fragment is the position of the first byte of 
        ///     the enclosing Movie Fragment Box, and for second and subsequent track fragments, the default is the 
        ///     end of the data defined by the preceding fragment. Fragments 'inheriting' their offset in this way 
        ///     must use the same data-reference (i.e., the data for these tracks must be in the same file). MUST be 1.
        /// 0x000002 (sample-description-index-present). Indicates the presence of this field, which overrides, in this fragment, 
        ///     the default set up in the Track Extends Box. For most common tracks, this field is 0 and the 
        ///     sample-description-index is omitted.
        /// 0x000008 (default-sample-duration-present). MUST be set to 0 if the <see cref="DefaultSampleDuration"/> is omitted.
        /// 0x000010 (default-sample-size-present). MUST be set to 0 if the <see cref="DefaultSampleSize"/> is omitted.
        /// 0x000020 (default-sample-flags-present). MUST be set to 0 if the <see cref="DefaultSampleFlags"/> is omitted.
        /// 0x010000 (duration-is-empty). Indicates that the duration provided in either <see cref="DefaultSampleDuration"/>, 
        ///     or by the default-duration in the Track Extends Box, is empty (i.e., there are no samples for this time interval). 
        ///     It is an error to make a presentation that has both edit lists in the Movie Box, and empty-duration fragments. 
        ///     MUST be 0 for Smooth Streaming.
        /// </summary>    
        public uint Flags { get; set; }

        /// <summary>
        /// Gets or sets the track id.
        /// </summary>       
        public uint TrackId { get; set; }

        /// <summary>
        /// Specifies the offset of the data field in the fragment’s mdat box, from the beginning of the moof box.
        /// </summary>
        public ulong BaseDataOffset { get; set; }

        /// <summary>
        /// Contains an index into the Sample Description table ('stsd') for this track. 
        /// The Track Extends Box ('trex') specifies a default sample description index. This field is needed only when 
        /// the track contains multiple sample types, and only for track fragments composed of samples that are not of 
        /// the default sample type
        /// </summary>
        public uint SampleDescriptionIndex { get; set; }

        /// <summary>
        /// Specifies the difference in decode time (in units of the timescale value of the mdhd box in the trak box with 
        /// the same <see cref="TrackId"/> as this tfhd box , usually 100 ns) between each sample.
        /// This field should be set for video tracks with a fixed frame rate. When the <see cref="DefaultSampleDuration"/> is 
        /// used, samples typically vary in size, so a per-sample sample_size is set in the Track Run box ('trun'), 
        /// and the <see cref="DefaultSampleSize"/> field is omitted.
        /// </summary> 
        public uint DefaultSampleDuration { get; set; }

        /// <summary>
        /// Specifies the size of each sample in bytes. This field should be set for audio tracks using a 
        /// fixed-size-per-sample encoding. When the <see cref="DefaultSampleSize"/> is used, samples typically vary in 
        /// duration, so a per-sample sample_size is set in the Track Run box ('trun'), and the <see cref="DefaultSampleSize"/> 
        /// field is omitted.
        /// </summary>
        public uint DefaultSampleSize { get; set; }

        public SampleFlags DefaultSampleFlags { get; set; }
    }

    public sealed class TrackFragmentRunBox : IFullBox
    {
        public TrackFragmentRunBox()
        {
            Type = "trun";
            Samples = new List<TrackFragmentRunSample>();
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        /// <summary>
        /// Added to the implicit or explicit data offset established in the track fragment header.
        /// </summary>
        public uint DataOffset { get; set; }

        /// <summary>
        /// Specifies the dependency and redundancy information for the first sample. 
        /// For a video track, the first sample in a fragment MUST be a seekable I-frame, and its sample_depends_on flag MUST be 2.
        /// </summary>
        public SampleFlags FirstSampleFlags { get; set; }

        /// <summary>
        /// Gets the list of samples.
        /// </summary>      
        public IList<TrackFragmentRunSample> Samples { get; private set; }
    }

    /// <summary>
    /// Defines information for each sample flags
    /// </summary>
    public sealed class TrackFragmentRunSample
    {
        /// <summary>
        /// Specifies the offset between the decode time and composition time.
        /// </summary>            
        public uint SampleCompositionTimeOffset { get; set; }
        /// <summary>
        /// Gets or sets the duration of the sample.
        /// </summary>            
        public uint SampleDuration { get; set; }
        /// <summary>
        /// Specifies the dependency and redundancy information for each sample. For B-frames and P-frames, the sample_depends_on flag MUST be 1 and the sample_is_depended_on 
        /// SHOULD be set to 1 if no B-frames depend on this sample (and 2 otherwise), but MAY be set to 0 if this information cannot be reliably determined.
        /// </summary>
        public SampleFlags SampleFlags { get; set; }
        /// <summary>
        /// Gets or sets the size of the sample.
        /// </summary>           
        public uint SampleSize { get; set; }
    }

    public sealed class IndependentAndDisposableSamplesBox : IFullBox
    {
        public IndependentAndDisposableSamplesBox()
        {
            Type = "sdtp";
            Samples = new List<IndependentAndDisposableSample>();
        }

        public string Type { get; set; }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        /// <summary>
        /// Gets the list of samples.
        /// </summary>      
        public IList<IndependentAndDisposableSample> Samples { get; private set; }
    }

    /// <summary>
    /// Describes each of the samples.
    /// </summary>
    public sealed class IndependentAndDisposableSample
    {
        /// <summary>
        /// This flag takes one of the following four values:
        ///     0: the dependency of this sample is unknown;
        ///     1: this sample does depend on others (not an I picture);
        ///     2: this sample does not depend on others (I picture);
        ///     3: reserved
        /// </summary>
        public int SampleDependsOn { get; set; }


        /// <summary>
        /// This flag takes one of the following three values:
        ///     0: it is unknown whether there is redundant coding in this sample;
        ///     1: there is redundant coding in this sample;
        ///     2: there is no redundant coding
        /// </summary>
        public int SampleHasRedundancy { get; set; }


        /// <summary>
        /// This flag takes one of the following four values:
        ///     0: the dependency of other samples on this sample is unknown;
        ///     1: other samples depend on this one (not disposable);
        ///     2: no other sample depends on this one (disposable);
        ///     3: reserved
        /// </summary>
        public int SampleIsDependedOn { get; set; }
    }

    public sealed class MediaDataBox : IBox
    {
        public MediaDataBox()
        {
            Type = "mdat";
        }

        public string Type { get; set; }
        public byte[] Data { get; set; }
    }

    public sealed class UnknownBox : IBox
    {
        public string Type { get; set; }
        public byte[] Data { get; set; }
    }

    public sealed class TrackFragmentExtendedHeaderBox : IUniversalUniqueIdentifierBox, IFullBox
    {
        public TrackFragmentExtendedHeaderBox()
        {
            Type = "uuid";
            Uuid = new Guid("6d1d9b05-42d5-44e6-80e2-141daff757b2");
        }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        public string Type { get; set; }

        public Guid Uuid { get; set; }

        public ulong FraqmentAbsoluteTime { get; set; }

        public ulong FragmentDuration { get; set; }
    }

    public sealed class LiveServerManifestBox : IUniversalUniqueIdentifierBox, IFullBox
    {
        public LiveServerManifestBox()
        {
            Type = "uuid";
            Uuid = new Guid("a5d40b30-e814-11dd-ba2f-0800200c9a66");
        }

        public byte Version { get; set; }

        public uint Flags { get; set; }

        public string Type { get; set; }

        public Guid Uuid { get; set; }

        public string Manifest { get; set; }
    }

    public sealed class SampleFlags
    {
        const int SizeDegradationPriority = 16;
        const int SizeIsDifferenceSample = 1;
        const int SizePaddingValue = 3;
        const int SizeHasRedundancy = 2;
        const int SizeIsDependedOn = 2;
        const int SizeDependsOn = 2;

        const int OffsetDegradationPriority = 0;
        const int OffsetIsDifferenceSample = OffsetDegradationPriority + SizeDegradationPriority;
        const int OffsetPaddingValue = OffsetIsDifferenceSample + SizeIsDifferenceSample;
        const int OffsetHasRedundancy = OffsetPaddingValue + SizePaddingValue;
        const int OffsetIsDependedOn = OffsetHasRedundancy + SizeHasRedundancy;
        const int OffsetDependsOn = OffsetIsDependedOn + SizeIsDependedOn;

        public SampleFlags() { }

        public SampleFlags(uint v) { SetValue(v); }

        public int DegradationPriority { get; set; }
        public bool IsDifferenceSample { get; set; }
        public int PaddingValue { get; set; }
        public int HasRedundancy { get; set; }
        public int IsDependedOn { get; set; }
        public int DependsOn { get; set; }

        public uint GetValue()
        {
            return (uint)(
                (DegradationPriority << OffsetDegradationPriority) +
                (IsDifferenceSample ? 1 : 0 << OffsetIsDifferenceSample) +
                (PaddingValue << OffsetPaddingValue) +
                (HasRedundancy << OffsetHasRedundancy) +
                (IsDependedOn << OffsetIsDependedOn) +
                (DependsOn << OffsetDependsOn)
                );
        }

        public void SetValue(uint value)
        {
            DegradationPriority = (int)value & GetMask(OffsetDegradationPriority, SizeDegradationPriority);
            IsDifferenceSample = ((int)value & GetMask(OffsetIsDifferenceSample, SizeIsDifferenceSample)) == 1;
            PaddingValue = (int)value & GetMask(OffsetPaddingValue, SizePaddingValue);
            HasRedundancy = (int)value & GetMask(OffsetHasRedundancy, SizeHasRedundancy);
            IsDependedOn = (int)value & GetMask(OffsetIsDependedOn, SizeIsDependedOn);
            DependsOn = (int)value & GetMask(OffsetDependsOn, SizeDependsOn);
        }

        static int GetMask(int offset, int size)
        {
            int result = 0;
            for (int i = 0; i < size; i++)
            {
                result = (result << 1) + 1;
            }
            return result << offset;
        }
    }
}